// Simple server.cpp
//
// modified by Brian Schick
// 4/29/2010

#include <stdio.h>      /* for printf(), fprintf() */
#include <Winsock2.h>    /* for socket(),... */
#include <stdlib.h>     /* for exit() */
#include <iostream>

#define RCVBUFSIZE 512  /* Size of receive buffer */
#define SRVR_ADDRESS	"127.0.0.1"
#define SRVR_PORT		7654

using namespace std;

void CloseGracefully( SOCKET s )
{
	// shutdown socket
	// close socket
	if ( s != INVALID_SOCKET )
	{
		if ( shutdown(s,SD_BOTH) == SOCKET_ERROR )
			printf("Socket shutdown failed with error: %d\n", WSAGetLastError() );
		if ( closesocket(s) == SOCKET_ERROR )
			printf("Socket closesocket failed with error: %d\n", WSAGetLastError() );
	}
	// cleanup WSA
	if ( WSACleanup() == SOCKET_ERROR )
		printf("WSA Cleanup failed with error: %d\n", WSAGetLastError() );
}

void DieWithError(char *errorMessage, int err, SOCKET s)
{
	if (err != -1) {
		fprintf(stderr,"%s: %d\n", errorMessage, err);

	} else {
		fprintf(stderr,"%s\n", errorMessage);
	}
	CloseGracefully( s );
}

void main(int argc, char *argv[])
{
    SOCKET servSock = SOCKET_ERROR;                    /* Socket descriptor for server */
    struct sockaddr_in srvr_addr; /* Local address */
    struct sockaddr_in clnt_addr; /* Client address */
    int clntLen =0;            /* Length of client address data structure */
	int err;
    WSADATA wsaData;                 /* Structure for WinSock setup communication */
	char recv_buf[RCVBUFSIZE];        /* Buffer for echo string */
	int recvMsgSize;                    /* Size of received message */

   
    if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) /* Load Winsock 2.0 DLL */
    {
        fprintf(stderr, "WSAStartup() failed");
		CloseGracefully( servSock );
        exit(1);
    }

    // Create socket for incoming connections
    //if ((servSock = socket(XXX)) == XXX)
	// params - address family (internet Ver 4), 
	//			socket type ( UDP datagrams ),
	//			protocol ( 0: let the provider choose [UDP] )
	if ((servSock = socket(AF_INET,SOCK_DGRAM,0)) == INVALID_SOCKET)
	{
        DieWithError("socket() failed", -1, servSock);
		exit(1);
	}

    // Construct local address structure
    //memset(XXX);		/* Zero out structure */
    memset(&srvr_addr,0,sizeof(sockaddr_in));		/* Zero out structure */
    srvr_addr.sin_family = AF_INET;					 /* Internet address family */
    //srvr_addr.sin_addr.s_addr = inet_addr(XXX); /* Any incoming interface */
    //srvr_addr.sin_port = htons(XXX);				/* listen port */
    srvr_addr.sin_addr.s_addr = inet_addr(SRVR_ADDRESS); /* Any incoming interface */
    srvr_addr.sin_port = htons(SRVR_PORT);				/* listen port */

    /* Bind to the local address */
    //if (bind(XXX) == XXX)
    if (bind(servSock, (SOCKADDR*)&srvr_addr, 
		sizeof(sockaddr_in)) == SOCKET_ERROR)
	{
        DieWithError("bind() failed", -1, servSock);
		exit(1);
	}

	for(;;)/* Run forever */
    {
        // Set the size of the in-out parameter
        clntLen = sizeof(clnt_addr);

		// Receive message from client
		//if ((recvMsgSize = recvfrom(XXX )) == XXX)
		if ( (recvMsgSize = recvfrom(servSock, 
				recv_buf, 
				RCVBUFSIZE * sizeof(char), 
				0,
				(SOCKADDR*) &clnt_addr,
				&clntLen
				) ) == SOCKET_ERROR)
		{

				if ((err = WSAGetLastError()) != WSAEMSGSIZE)
				{
						DieWithError("My UDP server: recvfrom() failed", err, servSock);
						exit(1);
				}
		} else	{
			recv_buf[recvMsgSize] = '\0';
			cout << "Message:" << recv_buf << "from " <<  inet_ntoa(clnt_addr.sin_addr) << ":" << ntohs(clnt_addr.sin_port) << endl;
		}
    }
    /* NOT REACHED */

	CloseGracefully( servSock );
}
